﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using NFL.Core;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net;
using System.Data;


namespace NFL.Business
{
    public class LiveScores
    {
        // Private variables
        DataAccess.DataAccess da;
        int _weekID;

        public LiveScores()
        {
            da = new DataAccess.DataAccess();
            
            // Get week ID
            _weekID = da.GetWeekID(DateTime.Now);

        }


        public bool GetLiveScores()
        {
            try
            {
                // See if time frame allows for another live check of scores to occur
                if (AllowLiveCheck())
                {
                    var games =  GetLiveScoresFromService();
                    PersistScores(games);
                }
                
            }
            catch (Exception)
            {
                return false;
            }

            return true;
        }

        public DataTable GetHeaderGamesRow()
        {
            try
            {
                // Header game row
                DataTable dt = new DataTable();

                // Setup columns for each of the games for the week
                var gamesForTheWeek = da.GetWeekGames(_weekID);

                // Get score info
                var scoreInfo = da.GetGameScores(_weekID);

                DataRow dr = dt.NewRow();

                foreach (var game in gamesForTheWeek)
                {
                    dt.Columns.Add(new DataColumn("Game" + game.SortOrder, Type.GetType("System.String")));
                    string homeTeam = da.GetTeamShortName(game.HomeTeam.Value);
                    string awayTeam = da.GetTeamShortName(game.AwayTeam.Value);
                    
                    // Get score info for this game
                    var specificGame = scoreInfo.Where(s => s.HomeTeam == game.HomeTeam && s.AwayTeam == game.AwayTeam).FirstOrDefault();
                    int homeScore = specificGame.HomeScore.Value;
                    int awayScore = specificGame.AwayScore.Value;
                    string gameStatus = specificGame.TimeStats;

                    string columnData = string.Format("{0} {1}\n{2} {3}\n{4}", awayTeam, awayScore, homeTeam, homeScore, gameStatus);

                    dr["Game" + game.SortOrder.Value.ToString()] = columnData;
                }


                dt.Rows.Add(dr);
                

                return dt;
            }
            catch
            {
                return null;
            }
        }

        public DataTable MergeHeaderAndData(DataTable dtHeader, DataTable dtData)
        {
            DataTable dt = new DataTable();

            try
            {
                dtHeader.Columns.Add("UserID").SetOrdinal(0);
                dtHeader.Columns.Add("Wins",Type.GetType("System.Int32")).SetOrdinal(1);
                dtHeader.Columns.Add("Losses", Type.GetType("System.Int32")).SetOrdinal(2);

                dt = dtHeader.Copy();

                dt.Merge(dtData);
                
                return dt;
            }
            catch 
            {
                return null;
            }
        }

        public DataTable BuildWeekGrid()
        {
            try
            {
                // data table to hold the grid
                DataTable dt = new DataTable();
        
                // Add user id column
                dt.Columns.Add(new DataColumn("UserID", Type.GetType("System.String")));

                // Add total wins
                dt.Columns.Add(new DataColumn("Wins", Type.GetType("System.Int32")));

                // Add total losses
                dt.Columns.Add(new DataColumn("Losses", Type.GetType("System.Int32")));


                foreach (var game in da.GetWeekGames(_weekID))
                {
                    dt.Columns.Add(new DataColumn("Game" + game.SortOrder, Type.GetType("System.String")));
                }

                // Add Monday night points
                dt.Columns.Add(new DataColumn("PTS", Type.GetType("System.Int32")));


                return dt;

            }
            catch (Exception ex)
            {

                return null;
            }
        }

        public DataTable FillWeekGrid(int division, DataTable dt)
        {
            try
            {
                // Get all users and their picks for the given week
                var allUsers = da.GetUsers(division);
                
                // Loop through each user and their pick and add a row to the week grid
                foreach (var usr in allUsers)
                {
                    // Create new gird row
                    DataRow dr = dt.NewRow();

                    // Move user id to row
                    dr["UserID"] = usr.UserID;

                    // Get all the picks for that user for that week
                    var userPicks = da.GetPicksForUser(usr.UserID, _weekID);

                    // Add those picks to the grid
                    foreach (var pick in userPicks)
                    {
                        // Get game column for grid
                        //string columnName = "Game" + pick.GameID.ToString();
                        string columnName = "Game" + pick.Game.SortOrder.ToString();
                        dr[columnName] = pick.Team.ShortName;
                    }

                    // Set the monday night points pick for the user
                    var totalPoints = userPicks.Where(u => u.TotalPoints != null).Select(u => u.TotalPoints).FirstOrDefault();
                    if (totalPoints.HasValue)
                    {
                        dr["PTS"] = totalPoints.Value;    
                    }
                    

                    dt.Rows.Add(dr);
                }

                return dt;
            }
            catch (Exception)
            {
                return null;
            }
        }


        public DataTable UpdateGridWinLossesWithScores(DataTable dt)
        {
            try
            {
                // Get the completed scores for the week
                var completedGames = da.GetCompletedGameScores(_weekID).ToList();

                foreach (DataRow row in dt.Rows)
                {
                    int win = 0;
                    int losses = 0;

                    var userPicks = da.GetPicksForUser(Convert.ToInt32(row["UserID"]), _weekID).ToList();

                    foreach (var gam in completedGames)
                    {
                        // If game is not a tie, calculate win/loss
                        if (gam.HomeScore != gam.AwayScore)
                        {
                            int winningTeam = 0;
                            if (gam.HomeScore > gam.AwayScore)
                            {
                                winningTeam = gam.HomeTeam.Value;
                            }
                            else
                            {
                                winningTeam = gam.AwayTeam.Value;
                            }


                            var winCount = userPicks.Where(p => p.TeamID.Value == winningTeam).Count();
                            if (winCount > 0)
                            {
                                win++;
                            }
                            else
                            {
                                losses++;
                            }
                        }
                        
                    }

                    row["wins"] = win;
                    row["losses"] = losses;
                }
                return dt;
            }
            catch 
            {
                return null;
            }
        
        }

        private bool AllowLiveCheck()
        {
            bool returnValue = false;

            try
            {
                // If its one of these days, skip all together
                if (DateTime.Now.DayOfWeek == DayOfWeek.Tuesday || DateTime.Now.DayOfWeek == DayOfWeek.Wednesday)
                {
                    return false;
                }


                // Get last time live scores where retrieved
                DateTime? lastScore = CacheItems.GetCachedItem(Enums.CacheItems.LastLiveScoreRetrieve) as DateTime?;
                
                // If no last score datetime available set to arbitrary past date to trigger retrieve of scores
                if (!lastScore.HasValue)
                {
                    lastScore = DateTime.MinValue;
                }

                // If this is a game day ( Thursday, Saturday, Sunday, or Monday )
                // allow live score update every 3 minutes, else just once a day.
                if (Core.Core.IsGameDay())
                {
                    if (DateTime.Now > lastScore.Value.AddMinutes(ConfigurationSettings.LiveScoreRefresh))
                    {
                        returnValue = true;
                    }
                }
                else
                {
                    if (lastScore.Value.Date < DateTime.Now.Date)
                    {
                        returnValue = true;
                    }
                }

            }
            catch 
            {
                return false;
            }

            return returnValue;

        }


        private IList<GameScore> GetLiveScoresFromService()
        {
            List<GameScore> games = new List<GameScore>();

            string rawData = string.Empty;
            using (WebClient wc = new WebClient())
            {
                wc.Credentials = CredentialCache.DefaultCredentials;
                rawData = wc.DownloadString(ConfigurationSettings.LiveScoreURL);
            }

            List<string> finalGames = FinalGames.GetFinalGames().ToList();

            string formatedData =  System.Web.HttpUtility.UrlDecode(rawData);

            string[] dataArr = formatedData.Split('&');

            foreach (var row in dataArr)
            {
                if (row.StartsWith("nfl_s_left"))
                {
                    string homeTeam = string.Empty;
                    int homeScore = 0;
                    string awayTeam = string.Empty;
                    int awayScore = 0;
                    string scoreStats = string.Empty;
                    bool final = false;
                    
                    string[] teamData = row.Split('=')[1].Split(' ');

                    int index = 0;
                    int trashInt = 0;

                    // Read elements until space is encountered to get away team name
                    while (!int.TryParse(teamData[index], out trashInt))
                    {
                        if (teamData[index] == "at")
                        {
                            index++;
                            break;                            
                        }
                        if (string.IsNullOrEmpty(awayTeam))
                        {
                            awayTeam = teamData[index];
                        }
                        else
                        {
                            awayTeam += " " + teamData[index];
                        }

                        index++;
                    }

                    // skip ahead to next non space
                    //while (string.IsNullOrEmpty(teamData[index]))
                    //{
                    //    index++;
                    //}

                    // if this element is numeric, then its a score 
                    if (int.TryParse(teamData[index], out trashInt))
                    {
                        awayScore = trashInt;
                        index++;

                        // skip ahead to next non space
                        while (string.IsNullOrEmpty(teamData[index]))
                        {
                            index++;
                        }
                    }


                    // Get home team name
                    while (!int.TryParse(teamData[index], out trashInt))
                    {
                        if (teamData[index].StartsWith("("))
                        {
                            index++;
                            break;
                        }
                        if (string.IsNullOrEmpty(homeTeam))
                        {
                            homeTeam = teamData[index];
                        }
                        else
                        {
                            homeTeam += " " + teamData[index];
                        }

                        index++;
                    }


                    //// skip ahead to next non space
                    //while (string.IsNullOrEmpty(teamData[index]))
                    //{
                    //    index++;
                    //}

                    // if this element is numeric, then its a score 
                    if (int.TryParse(teamData[index], out trashInt))
                    {
                        homeScore = trashInt;
                        index++;

                        // skip ahead to next non space
                        while (string.IsNullOrEmpty(teamData[index]))
                        {
                            index++;
                        }
                    }


                    // get final part of game stats
                    int startFinal = row.IndexOf('(');
                    //int endFinal = row.IndexOf(')');
                    scoreStats = row.Substring(startFinal);

                    //OLDif (scoreStats.Contains("FINAL") || (scoreStats.Contains("00:00") && (scoreStats.Contains("4TH") || scoreStats.Contains("OT"))) || scoreStats.Contains("END"))
                    
                    //if (scoreStats.Contains("FINAL") || (scoreStats.Contains("00:00") && scoreStats.Contains("OT")) || (scoreStats.Contains("END") && scoreStats.Contains("4TH")))
                    //{
                    //    final = true;
                    //}

                    // Check in the final games list if the game is in there, if so the game is complete and final.
                    if (finalGames.Contains(awayTeam.Replace('^', ' ').Replace(" ", string.Empty).Trim() + homeTeam.Replace('^', ' ').Replace(" ", string.Empty).Trim()))
                    {
                        final = true;
                    }

                    // Add game to games list
                    GameScore g = new GameScore();
                    g.AwayTeam = awayTeam.Replace('^', ' ').Trim();
                    g.AwayScore = awayScore;
                    g.HomeTeam = homeTeam.Replace('^', ' ').Trim();
                    g.HomeScore = homeScore;
                    g.Status = final ? "(FINAL)" : scoreStats;
                    g.Final = final;
                    games.Add(g);


                }

            }

            return games;
        }



        private void PersistScores(IList<GameScore> games)
        {
            foreach (var game in games)
            {
                // See if game already exists in database
                DataAccess.Score s = new DataAccess.Score();
                s.AwayTeam = da.GetTeamID(game.AwayTeam);
                s.AwayScore = game.AwayScore;
                s.HomeTeam = da.GetTeamID(game.HomeTeam);
                s.HomeScore = game.HomeScore;
                s.Final = game.Final;
                s.TimeStats = game.Status;
                s.WeekID = _weekID;

                da.PersistScore(s);

            }


            // Set persisted time to cache
            Core.CacheItems.SetCachedItem(Enums.CacheItems.LastLiveScoreRetrieve, DateTime.Now);
        }



        public bool? IsTeamWinner(string teamShortName, int weekID)
        {
            //bool returnValue = false;
            //int teamID = da.GetTeamID(teamShortName);
            //return scores.Contains(teamID);
            bool? returnValue = null;
            int teamID = da.GetTeamID(teamShortName);

            var score = da.GetSpecificScore(teamID, weekID);

            if (score != null)
            {
                if (score.HomeTeam == teamID)
                {
                    returnValue = score.HomeScore > score.AwayScore ? true : false;
                }
                else
                {
                    returnValue = score.AwayScore > score.HomeScore ? true : false;
                }
            }
            
            return returnValue;
            //foreach (var game in scores.ToList())
            //{
            //    int? winningTeam = game.AwayScore > game.HomeScore ? game.AwayTeam : game.HomeTeam;
            //    if (da.GetTeamID(teamShortName) == winningTeam.Value)
            //    {
            //        returnValue = true;
            //        break;
            //    }
            //}

        }


        public IList<WinnersLosers> GetWinnersLosers(int weekID)
        {
            try
            {
                // Winners and Losers
                List<WinnersLosers> winnersAndLosers = new List<WinnersLosers>();

                // Get completed games
                var completedGames = da.GetCompletedGameScores(weekID);

                foreach (var game in completedGames)
                {
                    // If game is not a tie, add to winners losers list
                    if (game.AwayScore != game.HomeScore)
                    {
                        WinnersLosers wl = new WinnersLosers();

                        if (game.AwayScore > game.HomeScore)
                        {
                            wl.WinningTeam = game.AwayTeam.Value;
                            wl.LosingTeam = game.HomeTeam.Value;
                        }
                        else
                        {
                            wl.WinningTeam = game.HomeTeam.Value;
                            wl.LosingTeam = game.AwayTeam.Value;
                        }

                        winnersAndLosers.Add(wl);
                    }
                    
                }

                return winnersAndLosers;
            }
            catch
            {
                return null;
            }
        }


        public IList<int> GetCompletedScores()
        {
            List<int> returnWinners = new List<int>();
            foreach (var game in da.GetCompletedGameScores(_weekID))
            {
                if (game.HomeScore > game.AwayScore)
                {
                    returnWinners.Add(game.HomeTeam.Value);                    
                }
                else
                {
                    returnWinners.Add(game.AwayTeam.Value);
                }
            }

            return returnWinners;
        }


        public List<int?> GetDivisions()
        {
            return da.GetDivisions().ToList();
        }


        public DataTable DetermineWinner(DataTable dt)
        {
            try
            {
                // Determine if the games are over; last game of the week is final
                if (da.IsWeekOver(_weekID))
                {
                    List<int> winners = new List<int>();

                    // See if their needs to be a check for points on tie breaker
                    DataRow[] result = dt.Select("WINS = MAX(wins)");

                    // Multiples exist, figure closest points to final game total score
                    if (result.Length > 1)
                    {
                        Dictionary<int,int> closestPoints = new Dictionary<int, int>();

                        int finalGameTotalScore = da.GetFinalGameTotalScore(_weekID);

                        foreach (var row in result)
                        {
                            int diff = Math.Abs(Convert.ToInt32(row["PTS"].ToString()) - finalGameTotalScore);
                            closestPoints.Add(Convert.ToInt32(row["UserID"].ToString()), diff);
                        }

                        // Get lowest difference from dictionary
                        int lowestDiff = closestPoints.OrderBy(c => c.Value).Select(c => c.Value).FirstOrDefault();
                        
                        // Get dictionary entry with user id = that with lowest diff
                        winners = closestPoints.Where(c => c.Value == lowestDiff).Select(c => c.Key).ToList();
                    }
                    else
                    {
                        // Get person with most wins, might be more than one
                        winners.Add(Convert.ToInt32(result[0]["UserID"].ToString()));
                    }

                     
                    // Loop through data table and put "*" next to winners ID
                    foreach (DataRow row in dt.Rows)
                    {
                        if (winners.Contains(Convert.ToInt32(row["UserID"].ToString())))
                        {
                            row["UserID"] += "*";
                        }
                    }


                }





                return dt;
            }
            catch 
            {
                return null;
            }
        }






    }
}
